// valid/ready protocol of pipeline 
module pipeline_ctrl(/*AUTOARG*/
   // Outputs
   o_pipeline_stage_en, o_valid, o_ready,
   // Inputs
   i_ready, i_valid, i_pipeline_stage_stall, clk, rst
   );
   parameter STAGE = 3;
   
   output logic [STAGE-1:0] o_pipeline_stage_en;
   
   output logic 			o_valid;
   input logic 				i_ready;
   
   input logic 				i_valid;
   output logic 			o_ready;

   input logic [STAGE-1:0] 	i_pipeline_stage_stall;
   input logic 				clk, rst;
   
   
   logic [STAGE+1:0] 		stage_valid_r, stage_valid_o, stage_ready;
   
   assign stage_valid_o[0] = i_valid;
   assign stage_ready[STAGE+1] = i_ready;
   
   generate
	  genvar 				i;
	  for(i=1;i<=STAGE;i++)
		begin : pipeline_ctrl_gen
		   always_ff@(posedge clk)
		   	 begin
		   		if(rst)
		   		  stage_valid_r[i] <= 1'b0;
		   		else if(stage_ready[i])
		   		  stage_valid_r[i] <= stage_valid_o[i-1];
		   	 end
		   assign stage_valid_o[i] = stage_valid_r[i] && !i_pipeline_stage_stall[i-1];
		   assign stage_ready[i] = !stage_valid_r[i] || (!i_pipeline_stage_stall[i-1] && stage_ready[i+1]);
		   assign o_pipeline_stage_en[i-1] = stage_ready[i] && stage_valid_o[i-1];
		end
   endgenerate

   assign o_ready = stage_ready[1];
   assign o_valid = stage_valid_o[STAGE];
   
endmodule // pipeline_ctrl

